package net.java.nioserver.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Channel;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.WritableByteChannel;

/**
 * @author Leonid Shlyapnikov
 */
public class ChannelUtil {

    private static final Logger log = LoggerFactory.getLogger(ChannelUtil.class);

    private ChannelUtil() {
    }

    public static void close(Channel channel) {
        if (null == channel) {
            return;
        }

        try {
            channel.close();
        } catch (IOException e) {
            log.warn("Cannot close channel: " + channel, e);
        }
    }

    public static void closeChannelCancelKey(SelectionKey key) {
        close(key.channel());
        key.cancel();
    }

    public static boolean readFromChannel(ReadableByteChannel readableChannel,
                                         ByteBuffer buffer) throws IOException {
        boolean result = true;

        final int bufferSize = buffer.remaining();

        // loop untill end of stream reached, all data read from the channel or buffer is filled up.
        for (int read = 0; read < bufferSize;) {

            final int justRead = readableChannel.read(buffer);

            if (-1 == justRead) {
                result = false; // end of stream reached or far end disconnected
                break;
            } else if (0 == justRead) {
                break;
            }

            read += justRead;
        }

        return result;
    }

    public static boolean readOneLineFromChannel(ReadableByteChannel readableChannel,
                                                 ByteBuffer buffer) throws IOException {
        boolean result = true;

        final int bufferSize = buffer.remaining();

        // loop untill end of stream reached, all data read from the channel or buffer is filled up.
        for (int read = 0; read < bufferSize;) {

            final int justRead = readableChannel.read(buffer);

            if (-1 == justRead) {
                result = false; // end of stream reached or far end disconnected
                break;
            } else if (0 == justRead ||
                    '\n' == buffer.get(buffer.position() - 1)) {
                break;
            }

            read += justRead;
        }

        return result;
    }

    public static void writeToChannel(ByteBuffer buffer,
                                      WritableByteChannel writableChannel) throws IOException {

        final int bufferSize = buffer.remaining();

        // loop untill all bytes are sent
        for (int written = 0; written < bufferSize;) {
            final int justWritten = writableChannel.write(buffer);
            written += justWritten;
        }
    }
}
